import { Hono } from "npm:hono";
import { cors } from "npm:hono/cors";
import { logger } from "npm:hono/logger";
import { sign, verify } from "npm:jsonwebtoken@9.0.2";
import * as kv from "./kv_store.tsx";

const app = new Hono();

// JWT Secret - in production, use environment variable
const JWT_SECRET = Deno.env.get("JWT_SECRET") || "your-secret-key-change-in-production";
const JWT_EXPIRES_IN = "7d";

// Enable logger
app.use('*', logger(console.log));

// Enable CORS for all routes and methods
app.use(
  "/*",
  cors({
    origin: "*",
    allowHeaders: ["Content-Type", "Authorization", "X-Auth-Token"],
    allowMethods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
    exposeHeaders: ["Content-Length"],
    maxAge: 600,
  }),
);

// Prefix for all routes
const PREFIX = "/make-server-5cc66405";

// ============================================================================
// HELPER FUNCTIONS
// ============================================================================

// Hash password using Web Crypto API
async function hashPassword(password: string): Promise<string> {
  const encoder = new TextEncoder();
  const data = encoder.encode(password);
  const hash = await crypto.subtle.digest("SHA-256", data);
  const hashArray = Array.from(new Uint8Array(hash));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

// Verify password
async function verifyPassword(password: string, hashedPassword: string): Promise<boolean> {
  const hash = await hashPassword(password);
  return hash === hashedPassword;
}

// Generate JWT token
function generateToken(userId: string, username: string, role: string): string {
  return sign(
    { userId, username, role },
    JWT_SECRET,
    { expiresIn: JWT_EXPIRES_IN }
  );
}

// Verify JWT token
function verifyToken(token: string): any {
  try {
    return verify(token, JWT_SECRET);
  } catch (error) {
    return null;
  }
}

// Middleware to verify authentication
async function authMiddleware(c: any, next: any) {
  // Check for JWT token in X-Auth-Token header
  const token = c.req.header("X-Auth-Token");
  
  if (!token) {
    return c.json({ error: "Unauthorized - No token provided" }, 401);
  }

  const decoded = verifyToken(token);

  if (!decoded) {
    return c.json({ error: "Unauthorized - Invalid or expired token" }, 401);
  }

  c.set("user", decoded);
  await next();
}

// Initialize default data
async function initializeData() {
  try {
    // Check if users already exist
    const existingUsers = await kv.getByPrefix("user:");
    
    if (existingUsers.length === 0) {
      console.log("Initializing default users...");
      
      // Create default admin user
      const adminPasswordHash = await hashPassword("password");
      const adminUser = {
        id: "user-1",
        username: "admin",
        email: "admin@example.com",
        password: adminPasswordHash,
        role: "admin",
        createdAt: new Date().toISOString()
      };
      
      await kv.set(`user:${adminUser.id}`, adminUser);
      await kv.set(`username:${adminUser.username}`, adminUser.id);
      
      console.log("Default admin user created (username: admin, password: password)");
    }
    
    // Check if databases already exist
    const existingDatabases = await kv.getByPrefix("database:");
    
    if (existingDatabases.length === 0) {
      console.log("Initializing sample databases...");
      
      const sampleDatabases = [
        {
          id: "db-1",
          name: "production-aurora",
          engine: "Aurora PostgreSQL",
          version: "15.4",
          status: "running",
          region: "us-east-1",
          instanceType: "db.r5.xlarge",
          storage: 250,
          connections: 45,
          cpu: 68,
          memory: 72,
          createdAt: new Date("2024-01-15T08:30:00.000Z").toISOString(),
          updatedAt: new Date("2024-01-15T08:30:00.000Z").toISOString()
        },
        {
          id: "db-2",
          name: "analytics-mysql",
          engine: "MySQL",
          version: "8.0.35",
          status: "running",
          region: "us-west-2",
          instanceType: "db.r5.large",
          storage: 100,
          connections: 23,
          cpu: 42,
          memory: 38,
          createdAt: new Date("2024-02-20T10:15:00.000Z").toISOString(),
          updatedAt: new Date("2024-02-20T10:15:00.000Z").toISOString()
        },
        {
          id: "db-3",
          name: "development-db",
          engine: "PostgreSQL",
          version: "14.9",
          status: "stopped",
          region: "us-east-1",
          instanceType: "db.t3.medium",
          storage: 50,
          connections: 0,
          cpu: 0,
          memory: 0,
          createdAt: new Date("2024-03-10T14:22:00.000Z").toISOString(),
          updatedAt: new Date("2024-03-10T14:22:00.000Z").toISOString()
        },
        {
          id: "db-4",
          name: "staging-redis",
          engine: "Redis",
          version: "7.0.12",
          status: "running",
          region: "eu-west-1",
          instanceType: "cache.r6g.large",
          storage: 25,
          connections: 12,
          cpu: 25,
          memory: 45,
          createdAt: new Date("2024-03-15T09:45:00.000Z").toISOString(),
          updatedAt: new Date("2024-03-15T09:45:00.000Z").toISOString()
        }
      ];
      
      for (const db of sampleDatabases) {
        await kv.set(`database:${db.id}`, db);
      }
      
      console.log(`${sampleDatabases.length} sample databases created`);
    }
    
    // Check if slow queries already exist
    const existingQueries = await kv.getByPrefix("slowquery:");
    
    if (existingQueries.length === 0) {
      console.log("Initializing sample slow queries...");
      
      const sampleQueries = [
        {
          id: "query-1",
          query: "SELECT * FROM orders o JOIN users u ON o.user_id = u.id WHERE o.created_at > '2024-01-01' ORDER BY o.total_amount DESC",
          duration: 4.25,
          database: "production-aurora",
          timestamp: new Date("2024-03-15T10:30:00.000Z").toISOString(),
          impact: "high",
          executionCount: 156,
          avgDuration: 3.8
        },
        {
          id: "query-2",
          query: "UPDATE user_sessions SET last_activity = NOW() WHERE user_id IN (SELECT id FROM users WHERE active = true)",
          duration: 2.15,
          database: "analytics-mysql",
          timestamp: new Date("2024-03-15T10:25:00.000Z").toISOString(),
          impact: "medium",
          executionCount: 89,
          avgDuration: 1.9
        },
        {
          id: "query-3",
          query: "SELECT COUNT(*) FROM analytics_events WHERE event_type = 'page_view' AND created_at BETWEEN '2024-03-01' AND '2024-03-15'",
          duration: 1.85,
          database: "analytics-mysql",
          timestamp: new Date("2024-03-15T10:20:00.000Z").toISOString(),
          impact: "low",
          executionCount: 45,
          avgDuration: 1.6
        }
      ];
      
      for (const query of sampleQueries) {
        await kv.set(`slowquery:${query.id}`, query);
      }
      
      console.log(`${sampleQueries.length} sample slow queries created`);
    }
    
    // Initialize storage data
    const existingStorage = await kv.getByPrefix("storage:");
    
    if (existingStorage.length === 0) {
      console.log("Initializing sample storage data...");
      
      const storageData = [
        { databaseId: "db-1", allocated: 250, used: 187, free: 63, utilization: 74.8 },
        { databaseId: "db-2", allocated: 100, used: 68, free: 32, utilization: 68.0 },
        { databaseId: "db-3", allocated: 50, used: 12, free: 38, utilization: 24.0 },
        { databaseId: "db-4", allocated: 25, used: 18, free: 7, utilization: 72.0 }
      ];
      
      for (const storage of storageData) {
        await kv.set(`storage:${storage.databaseId}`, storage);
      }
      
      console.log(`${storageData.length} storage records created`);
    }
    
  } catch (error) {
    console.error("Error initializing data:", error);
  }
}

// ============================================================================
// AUTHENTICATION ROUTES
// ============================================================================

// Login
app.post(`${PREFIX}/api/auth/login`, async (c) => {
  try {
    const { username, password } = await c.req.json();
    
    if (!username || !password) {
      return c.json({ error: "Username and password are required" }, 400);
    }
    
    // Get user ID from username
    const userId = await kv.get(`username:${username}`);
    
    if (!userId) {
      return c.json({ error: "Invalid credentials" }, 401);
    }
    
    // Get user data
    const user = await kv.get(`user:${userId}`);
    
    if (!user) {
      return c.json({ error: "Invalid credentials" }, 401);
    }
    
    // Verify password
    const isPasswordValid = await verifyPassword(password, user.password);
    
    if (!isPasswordValid) {
      return c.json({ error: "Invalid credentials" }, 401);
    }
    
    // Generate tokens
    const token = generateToken(user.id, user.username, user.role);
    const refreshToken = generateToken(user.id, user.username, user.role); // In production, use different logic for refresh token
    
    // Remove password from response
    const { password: _, ...userWithoutPassword } = user;
    
    return c.json({
      user: userWithoutPassword,
      token,
      refreshToken
    });
  } catch (error) {
    console.error("Login error:", error);
    return c.json({ error: "Login failed" }, 500);
  }
});

// Logout
app.post(`${PREFIX}/api/auth/logout`, authMiddleware, async (c) => {
  // In a real implementation, you might want to invalidate the token
  return c.json({ message: "Logged out successfully" });
});

// Refresh token
app.post(`${PREFIX}/api/auth/refresh`, async (c) => {
  try {
    const { refreshToken } = await c.req.json();
    
    if (!refreshToken) {
      return c.json({ error: "Refresh token is required" }, 400);
    }
    
    const decoded = verifyToken(refreshToken);
    
    if (!decoded) {
      return c.json({ error: "Invalid refresh token" }, 401);
    }
    
    // Get user data
    const user = await kv.get(`user:${decoded.userId}`);
    
    if (!user) {
      return c.json({ error: "User not found" }, 404);
    }
    
    // Generate new tokens
    const newToken = generateToken(user.id, user.username, user.role);
    const newRefreshToken = generateToken(user.id, user.username, user.role);
    
    // Remove password from response
    const { password: _, ...userWithoutPassword } = user;
    
    return c.json({
      user: userWithoutPassword,
      token: newToken,
      refreshToken: newRefreshToken
    });
  } catch (error) {
    console.error("Refresh token error:", error);
    return c.json({ error: "Token refresh failed" }, 500);
  }
});

// Get profile
app.get(`${PREFIX}/api/auth/profile`, authMiddleware, async (c) => {
  try {
    const userContext = c.get("user");
    const user = await kv.get(`user:${userContext.userId}`);
    
    if (!user) {
      return c.json({ error: "User not found" }, 404);
    }
    
    // Remove password from response
    const { password: _, ...userWithoutPassword } = user;
    
    return c.json(userWithoutPassword);
  } catch (error) {
    console.error("Get profile error:", error);
    return c.json({ error: "Failed to get profile" }, 500);
  }
});

// ============================================================================
// DATABASE INSTANCE ROUTES
// ============================================================================

// Get all databases
app.get(`${PREFIX}/api/databases`, authMiddleware, async (c) => {
  try {
    const databases = await kv.getByPrefix("database:");
    return c.json(databases);
  } catch (error) {
    console.error("Error fetching databases:", error);
    return c.json({ error: "Failed to fetch databases" }, 500);
  }
});

// Get single database
app.get(`${PREFIX}/api/databases/:id`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const database = await kv.get(`database:${id}`);
    
    if (!database) {
      return c.json({ error: "Database not found" }, 404);
    }
    
    return c.json(database);
  } catch (error) {
    console.error("Error fetching database:", error);
    return c.json({ error: "Failed to fetch database" }, 500);
  }
});

// Create database
app.post(`${PREFIX}/api/databases`, authMiddleware, async (c) => {
  try {
    const data = await c.req.json();
    
    const newDatabase = {
      id: `db-${Date.now()}`,
      name: data.name,
      engine: data.engine,
      version: data.version,
      status: "pending",
      region: data.region,
      instanceType: data.instanceType,
      storage: data.storage,
      connections: 0,
      cpu: 0,
      memory: 0,
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString()
    };
    
    await kv.set(`database:${newDatabase.id}`, newDatabase);
    
    // Simulate database provisioning - change status to running after a delay
    setTimeout(async () => {
      const db = await kv.get(`database:${newDatabase.id}`);
      if (db) {
        db.status = "running";
        db.connections = Math.floor(Math.random() * 20);
        db.cpu = Math.floor(Math.random() * 50);
        db.memory = Math.floor(Math.random() * 60);
        db.updatedAt = new Date().toISOString();
        await kv.set(`database:${newDatabase.id}`, db);
      }
    }, 3000);
    
    return c.json(newDatabase, 201);
  } catch (error) {
    console.error("Error creating database:", error);
    return c.json({ error: "Failed to create database" }, 500);
  }
});

// Update database
app.patch(`${PREFIX}/api/databases/:id`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const updates = await c.req.json();
    
    const database = await kv.get(`database:${id}`);
    
    if (!database) {
      return c.json({ error: "Database not found" }, 404);
    }
    
    const updatedDatabase = {
      ...database,
      ...updates,
      id: database.id, // Don't allow ID to be changed
      updatedAt: new Date().toISOString()
    };
    
    await kv.set(`database:${id}`, updatedDatabase);
    
    return c.json(updatedDatabase);
  } catch (error) {
    console.error("Error updating database:", error);
    return c.json({ error: "Failed to update database" }, 500);
  }
});

// Delete database
app.delete(`${PREFIX}/api/databases/:id`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const database = await kv.get(`database:${id}`);
    
    if (!database) {
      return c.json({ error: "Database not found" }, 404);
    }
    
    await kv.del(`database:${id}`);
    
    // Also delete associated storage data
    await kv.del(`storage:${id}`);
    
    return c.json({ message: "Database deleted successfully" });
  } catch (error) {
    console.error("Error deleting database:", error);
    return c.json({ error: "Failed to delete database" }, 500);
  }
});

// Start database
app.post(`${PREFIX}/api/databases/:id/start`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const database = await kv.get(`database:${id}`);
    
    if (!database) {
      return c.json({ error: "Database not found" }, 404);
    }
    
    database.status = "running";
    database.connections = Math.floor(Math.random() * 20) + 5;
    database.cpu = Math.floor(Math.random() * 50) + 10;
    database.memory = Math.floor(Math.random() * 60) + 20;
    database.updatedAt = new Date().toISOString();
    
    await kv.set(`database:${id}`, database);
    
    return c.json(database);
  } catch (error) {
    console.error("Error starting database:", error);
    return c.json({ error: "Failed to start database" }, 500);
  }
});

// Stop database
app.post(`${PREFIX}/api/databases/:id/stop`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const database = await kv.get(`database:${id}`);
    
    if (!database) {
      return c.json({ error: "Database not found" }, 404);
    }
    
    database.status = "stopped";
    database.connections = 0;
    database.cpu = 0;
    database.memory = 0;
    database.updatedAt = new Date().toISOString();
    
    await kv.set(`database:${id}`, database);
    
    return c.json(database);
  } catch (error) {
    console.error("Error stopping database:", error);
    return c.json({ error: "Failed to stop database" }, 500);
  }
});

// Restart database
app.post(`${PREFIX}/api/databases/:id/restart`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const database = await kv.get(`database:${id}`);
    
    if (!database) {
      return c.json({ error: "Database not found" }, 404);
    }
    
    database.status = "pending";
    database.updatedAt = new Date().toISOString();
    
    await kv.set(`database:${id}`, database);
    
    // Simulate restart
    setTimeout(async () => {
      const db = await kv.get(`database:${id}`);
      if (db) {
        db.status = "running";
        db.connections = Math.floor(Math.random() * 20) + 5;
        db.cpu = Math.floor(Math.random() * 50) + 10;
        db.memory = Math.floor(Math.random() * 60) + 20;
        db.updatedAt = new Date().toISOString();
        await kv.set(`database:${id}`, db);
      }
    }, 2000);
    
    return c.json(database);
  } catch (error) {
    console.error("Error restarting database:", error);
    return c.json({ error: "Failed to restart database" }, 500);
  }
});

// ============================================================================
// METRICS ROUTES
// ============================================================================

// Get metrics for a database
app.get(`${PREFIX}/api/databases/:id/metrics`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const database = await kv.get(`database:${id}`);
    
    if (!database) {
      return c.json({ error: "Database not found" }, 404);
    }
    
    // Generate mock metrics for the last 24 hours
    const metrics = Array.from({ length: 24 }, (_, i) => ({
      timestamp: new Date(Date.now() - (23 - i) * 60 * 60 * 1000).toISOString(),
      cpu: Math.random() * 30 + 40,
      memory: Math.random() * 25 + 50,
      connections: Math.floor(Math.random() * 20) + 30,
      iops: Math.floor(Math.random() * 1000) + 500
    }));
    
    return c.json(metrics);
  } catch (error) {
    console.error("Error fetching metrics:", error);
    return c.json({ error: "Failed to fetch metrics" }, 500);
  }
});

// Get current metrics
app.get(`${PREFIX}/api/databases/:id/metrics/current`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const database = await kv.get(`database:${id}`);
    
    if (!database) {
      return c.json({ error: "Database not found" }, 404);
    }
    
    const currentMetrics = {
      timestamp: new Date().toISOString(),
      cpu: database.cpu || 0,
      memory: database.memory || 0,
      connections: database.connections || 0,
      iops: Math.floor(Math.random() * 1000) + 500
    };
    
    return c.json(currentMetrics);
  } catch (error) {
    console.error("Error fetching current metrics:", error);
    return c.json({ error: "Failed to fetch current metrics" }, 500);
  }
});

// ============================================================================
// SLOW QUERIES ROUTES
// ============================================================================

// Get slow queries
app.get(`${PREFIX}/api/databases/slow-queries`, authMiddleware, async (c) => {
  try {
    const databaseId = c.req.query("databaseId");
    const limit = c.req.query("limit");
    
    let queries = await kv.getByPrefix("slowquery:");
    
    // Filter by database if specified
    if (databaseId) {
      const database = await kv.get(`database:${databaseId}`);
      if (database) {
        queries = queries.filter(q => q.database === database.name);
      }
    }
    
    // Apply limit if specified
    if (limit) {
      queries = queries.slice(0, parseInt(limit));
    }
    
    return c.json(queries);
  } catch (error) {
    console.error("Error fetching slow queries:", error);
    return c.json({ error: "Failed to fetch slow queries" }, 500);
  }
});

// Optimize query
app.post(`${PREFIX}/api/databases/slow-queries/:id/optimize`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const query = await kv.get(`slowquery:${id}`);
    
    if (!query) {
      return c.json({ error: "Query not found" }, 404);
    }
    
    // Return mock optimization suggestions
    const suggestions = [
      "Add an index on frequently queried columns",
      "Consider using LIMIT to reduce result set size",
      "Replace SELECT * with specific column names",
      "Use query caching for frequently executed queries"
    ];
    
    return c.json({ suggestions });
  } catch (error) {
    console.error("Error optimizing query:", error);
    return c.json({ error: "Failed to optimize query" }, 500);
  }
});

// Explain query
app.post(`${PREFIX}/api/databases/slow-queries/:id/explain`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const query = await kv.get(`slowquery:${id}`);
    
    if (!query) {
      return c.json({ error: "Query not found" }, 404);
    }
    
    // Return mock explain plan
    const plan = {
      type: "Sequential Scan",
      cost: "0.00..155.50",
      rows: 1550,
      width: 128
    };
    
    return c.json({ plan });
  } catch (error) {
    console.error("Error explaining query:", error);
    return c.json({ error: "Failed to explain query" }, 500);
  }
});

// Kill query
app.post(`${PREFIX}/api/databases/slow-queries/:id/kill`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const query = await kv.get(`slowquery:${id}`);
    
    if (!query) {
      return c.json({ error: "Query not found" }, 404);
    }
    
    // Delete the query
    await kv.del(`slowquery:${id}`);
    
    return c.json({ message: "Query killed successfully" });
  } catch (error) {
    console.error("Error killing query:", error);
    return c.json({ error: "Failed to kill query" }, 500);
  }
});

// ============================================================================
// STORAGE ROUTES
// ============================================================================

// Get storage usage
app.get(`${PREFIX}/api/databases/storage`, authMiddleware, async (c) => {
  try {
    const databaseId = c.req.query("databaseId");
    
    if (databaseId) {
      const storage = await kv.get(`storage:${databaseId}`);
      return c.json(storage || { databaseId, allocated: 0, used: 0, free: 0, utilization: 0 });
    }
    
    // Return all storage data
    const storageData = await kv.getByPrefix("storage:");
    return c.json(storageData);
  } catch (error) {
    console.error("Error fetching storage:", error);
    return c.json({ error: "Failed to fetch storage data" }, 500);
  }
});

// Get storage growth
app.get(`${PREFIX}/api/databases/:id/storage/growth`, authMiddleware, async (c) => {
  try {
    const id = c.req.param("id");
    const days = parseInt(c.req.query("days") || "30");
    
    const database = await kv.get(`database:${id}`);
    
    if (!database) {
      return c.json({ error: "Database not found" }, 404);
    }
    
    // Generate mock growth data
    const growthData = Array.from({ length: days }, (_, i) => ({
      date: new Date(Date.now() - (days - i - 1) * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
      used: database.storage * 0.5 + (Math.random() * database.storage * 0.3),
      allocated: database.storage
    }));
    
    return c.json(growthData);
  } catch (error) {
    console.error("Error fetching storage growth:", error);
    return c.json({ error: "Failed to fetch storage growth" }, 500);
  }
});

// ============================================================================
// HEALTH CHECK
// ============================================================================

app.get(`${PREFIX}/health`, (c) => {
  return c.json({ status: "ok", timestamp: new Date().toISOString() });
});

// Initialize data on startup
initializeData();

Deno.serve(app.fetch);